package com.maycurobj.service.impl.opdca;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.maycur.developer.sdk.common.exception.MaycurException;
import com.maycur.developer.sdk.maycur.ultimate.openapi.request.PostReceiveApplicationRequest;
import com.maycur.developer.sdk.maycur.ultimate.openapi.request.form.GetFormPreconsumeRequest;
import com.maycur.developer.sdk.maycur.ultimate.openapi.request.form.PostFormPreconsumeRequest;
import com.maycur.developer.sdk.maycur.ultimate.openapi.response.PostReceiveApplicationResponse;
import com.maycur.developer.sdk.maycur.ultimate.openapi.response.form.GetFormPreconsumeResponse;
import com.maycurobj.domain.maycurDTO.BpmItineraryDTO;
import com.maycurobj.domain.maycurDTO.MayCurDefinedCol;
import com.maycurobj.entity.bpm.JobNumberDTO;
import com.maycurobj.entity.bpm.SalePlanOPDCADTO;
import com.maycurobj.repository.bpm.JobNumberMapper;
import com.maycurobj.repository.bpm.SalePlanOPDCAMapper;
import com.maycurobj.service.convert.BpmTravelToMC;
import com.maycurobj.service.http.HttpAPIService;
import com.maycurobj.service.http.MaycurApiService;
import com.maycurobj.util.NormalUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import static com.maycurobj.util.NormalUtil.null2Long;
import static com.maycurobj.util.NormalUtil.null2String;
import static com.maycurobj.util.opdca.OpdcaUtil.resultMap;

/**
 * 中间件opdca的处理层
 */
@Service
@Slf4j
public class OPDCAServiceImpl {

    @Autowired
    private MaycurApiService maycurApiService;

    @Autowired
    private BpmTravelToMC bpmTravelToMC;

    @Value("${maycurprop.openapiurl}")
    private String MCAPI;

    @Autowired
    private SalePlanOPDCAMapper salePlanOPDCAMapper;

    @Autowired
    private JobNumberMapper jobNumberMapper;

    @Autowired
    private CloseableHttpClient httpClient;

    @Autowired
    private RequestConfig config;

    //客户包含一致性检查用
    private String[] MCSTR = {"住宿", "飞机", "火车", "长途汽车", "长途船舶", "地铁/公交/轮渡", "出租车", "业务招待费"};

    //消费客户与行程客户一致性用
    //行程时间与消费时间一致性校验使用
    private String[] MCSTR2 = {"飞机", "火车", "长途汽车", "长途船舶", "地铁/公交/轮渡", "出租车", "业务招待费"};


    /**
     * 获取每刻的申请单
     *
     * @param code
     */
    public GetFormPreconsumeResponse getMayCurPreconsume(String code) throws MaycurException {
        GetFormPreconsumeRequest request = new GetFormPreconsumeRequest();
        request.setFormCode(code);
        GetFormPreconsumeResponse response = maycurApiService.getMaycurOpenApiClient().execute(request);
        return response;
    }

    /**
     * 导入每刻申请单，from bpm
     *
     * @return
     */
    public synchronized PostReceiveApplicationResponse importReferenceToMayCur(BpmItineraryDTO dto) throws Exception {
        //转化类型
        PostReceiveApplicationRequest request = bpmTravelToMC.bpmToMC(dto);
        //发送请求
        PostReceiveApplicationResponse response = maycurApiService.getMaycurOpenApiClient().execute(request);
        return response;
    }

    /**
     * 接受bpm objid 推送 每刻行程记录
     * @param objId
     */
    public String manualHandleBpmTravelService(String objId){
        //通过数据库获取对象
        try {
            SalePlanOPDCADTO entity = salePlanOPDCAMapper.getEntity(objId);
            //转化为bpmiteneraryDTO
            BpmItineraryDTO entityRes = privateBpmToServiceDto(entity);
            PostReceiveApplicationResponse response=importReferenceToMayCur(entityRes);
            Map<String, Object> ret = resultMap(response.getCode(), response.getMessage(), response.getData());
            //更新对象 字段信息
            Map<String, Object> ret2 = new HashMap<>();
            ret2.put("id", objId);
            ret2.put("responseMsg", JSONObject.toJSONString(ret));
            updateBpmOPDCAEntity(JSONObject.toJSONString(ret2));
            return "每刻结果:"+JSONObject.toJSONString(ret);
        } catch (Exception e) {
            log.info("------异常>>>>{}", e.toString());
            return "程序报错!";
        }

    }

    /**
     * 接受bpm objid 推送 每刻行程记录
     * @param seqNo
     */
    public String manualHandleBpmTravelBySeqNoService(String seqNo){
        //通过数据库获取对象
        try {
            SalePlanOPDCADTO entity = salePlanOPDCAMapper.getEntityBySeqNo(seqNo);
            //转化为bpmiteneraryDTO
            BpmItineraryDTO entityRes = privateBpmToServiceDto(entity);
            PostReceiveApplicationResponse response=importReferenceToMayCur(entityRes);
            Map<String, Object> ret = resultMap(response.getCode(), response.getMessage(), response.getData());
            //更新对象 字段信息
            Map<String, Object> ret2 = new HashMap<>();
            ret2.put("id", entity.getId());
            ret2.put("responseMsg", JSONObject.toJSONString(ret));
            updateBpmOPDCAEntity(JSONObject.toJSONString(ret2));
            return "每刻结果:"+JSONObject.toJSONString(ret);
        } catch (Exception e) {
            log.info("------异常>>>>{}", e.toString());
            return "程序报错!";
        }

    }

    public void updateBpmOPDCAEntity(String ret) {
        try {
            String url="http://172.17.100.12/api/api/integration/bpmObjectCompile/backEnd/updateObjectInstance";
            // 声明httpPost请求
            HttpPost httpPost = new HttpPost(url);
            // 加入配置信息
            httpPost.setConfig(config);

            if (ret != null) {
                // 判断map是否为空，不为空则进行遍历，封装from表单对象
                StringEntity stringEntity = new StringEntity(ret, "utf-8");
                stringEntity.setContentEncoding("UTF-8");
                httpPost.setEntity(stringEntity);
                httpPost.setHeader("Content-Type", "application/json;charset=utf-8");
                httpPost.setHeader("schemaCode","salePlan_OPDCA");

                // 发起请求
                CloseableHttpResponse response = this.httpClient.execute(httpPost);
                if (response.getStatusLine().getStatusCode() == 200) {
                    log.info("updateBpmEntity更新成功!!!!");
                }else{
                    log.info("updateBpmEntity更新失败!!!!");
                }
                response.close();
            }
        } catch (IOException e) {
            log.info("请求BPM 更新返回值异常");
        }
    }
    private BpmItineraryDTO privateBpmToServiceDto(SalePlanOPDCADTO entity) {
        JSONArray _partArray=null;
        if (StringUtils.isNotBlank(entity.getParticipants())) {
            _partArray=JSONArray.parseArray(entity.getParticipants());
        }
        entity.setParticipants(null);
        BpmItineraryDTO retDto =JSONObject.toJavaObject(JSON.parseObject(JSONObject.toJSONString(entity)), BpmItineraryDTO.class);
        //整理下多人员的信息
        if(!Objects.isNull(_partArray)){
            List<JobNumberDTO> _list = new ArrayList<>();
            //根据id获取 工号
            for (Object _obj : _partArray) {
                JSONObject __obj = (JSONObject) _obj;
                JobNumberDTO _empNo=jobNumberMapper.getUserID(__obj.getString("id"));
                _list.add(_empNo);
            }
            retDto.setJobNumber(_list);
        }
        return retDto;
    }

    /**
     * 停用 每刻OPDCA 行程申请单
     */
    public String disableReferenceToMayCur(String code) {
        try {
            JSONObject access_token = maycurApiService.getToken();
            String url = String.format("%s%s", MCAPI, "/form/preconsume/disable");
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("preConsumeCode", code);
            String ret = maycurApiService.doPostForMaycur(url, access_token, jsonObject.toJSONString());
            log.info("停用OPDCA 申请单结果----->{}", ret);
            return ret;
        }catch (Exception e){
            log.info("停用失败，单据号----->{}",code);
            return null;
        }
    }

    /**
     * 停用 每刻OPDCA 行程申请单 不需要返回值
     */
    public void disableReference(String code) {
        try {
            JSONObject access_token = maycurApiService.getToken();
            String url = String.format("%s%s", MCAPI, "/form/preconsume/disable");
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("preConsumeCode", code);
            String ret = maycurApiService.doPostForMaycur(url, access_token, jsonObject.toJSONString());
            log.info("停用OPDCA 申请单结果----->{}", ret);
        }catch (Exception e){
            log.info("停用失败，单据号----->{}",code);
        }
    }

    /**
     * 作废每刻OPDCA行程单
     *
     * @param code
     * @return
     * @throws Exception
     */
    public String nullReferenceToMayCur(String code) throws Exception {
        JSONObject access_token = maycurApiService.getToken();
        String url = String.format("%s%s", MCAPI, "/form/preconsume/" + code);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("reason", "接口作废");
        String ret = maycurApiService.doPutForMaycur(url, access_token, jsonObject.toJSONString());
        log.info("作废OPDCA 申请单结果----->{}", ret);
        return ret;
    }


    /**
     * 对每刻 报销单进行校验
     *
     * @param formData
     */
    public List<Map<String, Object>> validationForCustom(JSONObject formData) {
        //增加出差类型校验 参加内部会议 参加培训 参加会议会展 整单不校验
        boolean flag = checkFormOutType(formData);
        List<Map<String, Object>> retList = new ArrayList<>();
        if (!flag) {
            //检查行程客户和费用客户不一致 时间区间 一致性校验
            Map<String, Object> ret1 = checkAccountTravel(formData);
            //行程时间与消费时间 最早、最晚 一致性校验
            Map<String, Object> ret2 = checkTravelExpenseTimeVilidation(formData);
            //发票时间 与消费时间一致性校验
            Map<String, Object> ret3 = checkInvoice(formData);
            System.out.println("检查结果1---->>>" + ret1);
            System.out.println("检查结果2---->>>" + ret2);
            System.out.println("检查结果3---->>>" + ret3);
            retList.add(ret1);
            retList.add(ret2);
            retList.add(ret3);
        }else{
            Map<String, Object> ret1=retMap(true,"校验通过(参加内部会议不做校验)");
            retList.add(ret1);
        }


        return retList;

    }

    /**
     * 校验单据类型
     * @param formData
     * @return
     */
    private boolean checkFormOutType(JSONObject formData) {
        try {
            String formType = formData.getJSONObject("CF60").getJSONObject("value").getString("businessCode");
            //编码 RDD2111181U38G4QO = 参加内部会议  RDD2111181U2Y4DMO= 参加培训  RDD2111181U2IIFB4 = 参加会议会展
            if (formType.equals("RDD2111181U38G4QO") || formType.equals("RDD2111181U2Y4DMO") || formType.equals("RDD2111181U2IIFB4")) {
                return true;
            }
        } catch (Exception e) {
            log.info("checkFormOutType 校验单据类型出现异常");
            return false;
        }
        return false;
    }

    /**
     * 检查发票时间和消费时间不一致
     * 1.发票识别时间为空的 跳过
     * 2.错误提示（费用类型，金额，识别票的日期）
     */
    private Map<String, Object> checkInvoice(JSONObject formData) {
        StringBuilder sb = new StringBuilder();
        //获取费用
        JSONArray expenseArray = getObjectArray("expenseList", "value", formData);
        Map<ExpenseEntity, List<Long>> expenseEntityListMap = new HashMap<>();
        for (Object obj : expenseArray) {
            JSONObject _json = JSONObject.parseObject(JSONObject.toJSONString(obj));
            ExpenseEntity expenseEntity = new ExpenseEntity();
            String expenseTypeName = iterateJson(_json.getJSONObject("expenseTypeCode"), "text").toString();
            expenseEntity.setExpenseTypeName(expenseTypeName);
            List<String> _list = Arrays.asList(MCSTR);
            if (!_list.contains(expenseTypeName)) {
                continue;
            }
            List<Long> issueDates = new ArrayList<>();
            try {
                //如果没有发票信息,是通过第三方平台进行的消费,不做校验
                if(!_json.containsKey("invoiceList")){
                    log.info("通过第三方平台进行消费,不校验!---->>");
                    continue;
                }
                JSONArray _invoiceArray = _json.getJSONObject("invoiceList").getJSONArray("value");
                expenseEntity.setConsumeAmount(iterateJson(_json.getJSONObject("consumeAmount"), "text").toString());
                expenseEntity.setStartTime(longDateToShortLongDate(null2Long(iterateJson(_json.getJSONObject("consumeTime"), "startTime"))));
                expenseEntity.setEndTime(longDateToShortLongDate(null2Long(iterateJson(_json.getJSONObject("consumeTime"), "endTime"))));
                //增加业务招待，没有时间区间的日期处理
                if (expenseEntity.getStartTime()==0 && expenseEntity.getEndTime()==0) {
                    String _currentTimeStr = null2String(iterateJson(_json.getJSONObject("consumeTime"), "text"));
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                    Date date = sdf.parse(_currentTimeStr);
                    expenseEntity.setStartTime(date.getTime());
                    expenseEntity.setEndTime(date.getTime());
                }
                expenseEntity.setAmountStr(_json.getJSONObject("consumeAmount").getString("amountStr"));
                for (Object _obj : _invoiceArray) {
                    JSONObject __json = JSONObject.parseObject(JSONObject.toJSONString(_obj));
                    JSONObject _invoiceInfo = __json.getJSONObject("invoiceInfo");
                    if (!Objects.isNull(_invoiceInfo)) {
                        issueDates.add(getDateField(_invoiceInfo));
                    }
                }
            } catch (Exception e) {
                //发票组为空的
                log.info("发票和消费时间比较爆出异常------>>");
                e.printStackTrace();
                continue;
            }
            //加入到map中
            expenseEntityListMap.put(expenseEntity, issueDates);
        }

        //开始校验
        for (Map.Entry<ExpenseEntity, List<Long>> entry : expenseEntityListMap.entrySet()) {
            //todo:临时增加条件 行程有任意三月份的记录 不控制 .过几个月后删除
            if(entry.getKey().getStartTime()<=1709222400000l){
                return retMap(true,"发票时间与消费时间一致性检查通过-0301");
            }
            //校验 发票日期 是否在消费日期中
            if (!entry.getValue().isEmpty()) {
                List<Long> _list = entry.getValue();
                for (Long l : _list) {
                    if (l != 0) {
                        if (l < entry.getKey().getStartTime() || l > entry.getKey().getEndTime()) {
                            sb.append("费用记录：" + entry.getKey().getExpenseTypeName() + " " + entry.getKey().getConsumeAmount() + " 消费日期和该费用下提交的发票日期不同;");
                        }
                    }

                }
            }
        }

        //只做提醒
        return sb.length() > 0 ? retMap(true, sb.toString()) : retMap(true, "发票消费时间一致性检查通过");
    }

    /**
     * 检查行程客户和费用客户不一致 暂时为弱控 填写理由即可
     * 返回Map flag + message
     */
    private Map<String, Object> checkAccountTravel(JSONObject formData) {
        List<TravelEntity> travelList = null;
        List<ExpenseEntity> expenseList = null;
        try {
            //获取行程客户与时间
            JSONArray travelArray = getObjectArray("travelRouteList", "value", formData);
            if (Objects.isNull(travelArray) || travelArray.isEmpty()) {
                //费用空的
                return retMap(false, "行程是空的，无法校验\n");
            }
            //整理行程中的客户与时间
            travelList = new ArrayList<>();
            for (Object obj : travelArray) {
                TravelEntity _entity = new TravelEntity();
                JSONObject _json = JSONObject.parseObject(JSONObject.toJSONString(obj));
                if(!_json.getJSONObject("customObject").containsKey("CF208")){
                    //如果不包含 可能是过渡期的结果 直接返回
                    return retMap(true, "行程中的客户信息不存在,请补全-0301");
                }
                String accountName = iterateJson(_json.getJSONObject("customObject").getJSONObject("CF208"), "text").toString();
                Long startTime = dateToLong(iterateJson(_json.getJSONObject("travelTime"), "startTimeText"));
                Long endTime = dateToLong(iterateJson(_json.getJSONObject("travelTime"), "endTimeText"));
                _entity.setAccountName(StringUtils.isNotBlank(accountName) ? accountName : "无客户");
                _entity.setStartDate(startTime);
                _entity.setEndDate(endTime);
                travelList.add(_entity);
            }

            //获取费用客户与消费时间
            JSONArray expenseArray = getObjectArray("expenseList", "value", formData);
            if (Objects.isNull(expenseArray) || expenseArray.isEmpty()) {
                //费用空的
                return retMap(false, "费用是空的，无法校验\n");
            }
            //整理费用中的客户与时间
            expenseList = new ArrayList<>();
            for (Object obj : expenseArray) {
                JSONObject _json = JSONObject.parseObject(JSONObject.toJSONString(obj));
                //挑选需要计算包含关系的费用明细
                String expenseTypeName = iterateJson(_json.getJSONObject("expenseTypeCode"), "text").toString();
                List<String> _list = Arrays.asList(MCSTR2);
                if (!_list.contains(expenseTypeName)) {
                    continue;
                }
                ExpenseEntity _entity = new ExpenseEntity();
                //iterateJson(_json.getJSONObject("CF80"), "text").toString();
                String accountName = getTravelOutAndInAccountName(_json);
                Long startTime = dateToLong(iterateJson(_json.getJSONObject("consumeTime"), "startTimeText"));
                Long endTime = dateToLong(iterateJson(_json.getJSONObject("consumeTime"), "endTimeText"));
                _entity.setAccountName(StringUtils.isNotBlank(accountName) ? specialStringHandle(accountName) : "无客户");
                _entity.setStartTime(startTime);
                _entity.setEndTime(endTime);
                _entity.setAmountStr(iterateJson(_json.getJSONObject("consumeAmount"),"text").toString());
                if (_entity.getStartTime() == 0 && _entity.getEndTime() == 0) {
                    String currentTime = null2String(iterateJson(_json.getJSONObject("consumeTime"), "text"));
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                    Date date = sdf.parse(currentTime);
                    _entity.setStartTime(date.getTime());
                    _entity.setEndTime(date.getTime());
                }
                expenseList.add(_entity);
            }
        } catch (Exception e) {
            log.info("客户校验报出异常---输出异常的报文--->>{}", JSONObject.toJSONString(getObjectArray("travelRouteList", "value", formData)));
            return retMap(false, "校验异常，请通知管理员!");
        }

        StringBuilder sb = new StringBuilder();
        //费用 与 行程 客户时间关系进行 校验
        for (ExpenseEntity expenseEntity : expenseList) {
            boolean flag = false;
            String _accountName = expenseEntity.getAccountName();
            long _startTime = expenseEntity.getStartTime();
            long _endTime = expenseEntity.getEndTime();
            for (TravelEntity travelEntity : travelList) {
                //todo:临时增加条件 行程明细有任意一行三月份的记录 不控制 .过几个月后删除
                if(travelEntity.getStartDate()<=1709222400000l || _startTime<=1709222400000l){
                    return retMap(true, "行程与费用中客户及消费时间一致性校验通过-0301");
                }

                if (travelEntity.getAccountName().equals(_accountName)) {
                    //客户相同，时间校验
                    if (travelEntity.getStartDate() <= _startTime && travelEntity.getEndDate() >= _endTime) {
                        //符合要求
                        flag = true;
                    }

                }
            }
            if (!flag) {
                sb.append("  " + expenseEntity.getAmountStr() + "元的费用客户与行程客户无法匹配；");
            }
        }

        //整理提示
        if (sb.length() > 0) {
            sb.insert(0, "行程费用不一致：");
            sb.insert(sb.length(), " 提示:请保持 费用客户与行程客户 的一致性!");
        }

        return sb.length() > 0 ? retMap(true, sb.toString()) : retMap(true, "行程与费用中客户及消费时间一致性校验通过");
    }

    //获取客户名称 要区别 行程内,行程外
    private String getTravelOutAndInAccountName(JSONObject _json) {
        if(_json.containsKey("CF80")){
           return iterateJson(_json.getJSONObject("CF80"), "text").toString();
        }
        if (_json.containsKey("CF143")) {
            return iterateJson(_json.getJSONObject("CF143"), "text").toString();
        }
        return null;
    }

    /**
     * 行程 与 消费时间的吻合性校验
     */
    private Map<String,Object> checkTravelExpenseTimeVilidation(JSONObject formData){
        List<TravelEntity> travelList = null;
        List<ExpenseEntity> expenseList = null;
        //获取行程 时间
        JSONArray travelArray = getObjectArray("travelRouteList", "value", formData);
        if (Objects.isNull(travelArray) || travelArray.isEmpty()) {
            //费用空的
            return retMap(false, "行程是空的，无法校验\n");
        }
        //整理行程时间
        travelList = new ArrayList<>();
        for (Object obj : travelArray) {
            TravelEntity _entity = new TravelEntity();
            JSONObject _json = JSONObject.parseObject(JSONObject.toJSONString(obj));
            if(!_json.getJSONObject("customObject").containsKey("CF208")){
                //没有自定义项 直接报错
                return retMap(true, "行程没有客户，请说明原因!");
            }
            String accountName = iterateJson(_json.getJSONObject("customObject").getJSONObject("CF208"), "text").toString();
            Long startTime = dateToLong(iterateJson(_json.getJSONObject("travelTime"), "startTimeText"));
            Long endTime = dateToLong(iterateJson(_json.getJSONObject("travelTime"), "endTimeText"));
            _entity.setStartDate(startTime);
            _entity.setEndDate(endTime);
            travelList.add(_entity);
        }

        //获取费用消费时间
        JSONArray expenseArray = getObjectArray("expenseList", "value", formData);
        if (Objects.isNull(expenseArray) || expenseArray.isEmpty()) {
            //费用空的
            return retMap(false, "费用是空的，无法校验\n");
        }
        //整理费用中的时间
        expenseList = new ArrayList<>();
        for (Object obj : expenseArray) {
            JSONObject _json = JSONObject.parseObject(JSONObject.toJSONString(obj));
            //挑选需要计算包含关系的费用明细
            String expenseTypeName = iterateJson(_json.getJSONObject("expenseTypeCode"), "text").toString();
            List<String> _list = Arrays.asList(MCSTR2);
            if (!_list.contains(expenseTypeName)) {
                continue;
            }
            ExpenseEntity _entity = new ExpenseEntity();
            //费用时间取数调整
            Long startTime=0l;
            if(iterateJson(_json.getJSONObject("consumeTime"), "startTimeText")==null){
                 startTime = dateToLong(iterateJson(_json.getJSONObject("consumeTime"), "text"));
            }else{
                startTime = dateToLong(iterateJson(_json.getJSONObject("consumeTime"), "startTimeText"));
            }
//            Long startTime = dateToLong(iterateJson(_json.getJSONObject("consumeTime"), "startTimeText"));
            System.out.println("打印时间校验内容===>>startTime=" + startTime + "||expenseTypeName==>" + expenseTypeName+"||对应费用金额为:"+iterateJson(_json.getJSONObject("acceptAmount"),"text"));
            Long endTime=0l;
            if (iterateJson(_json.getJSONObject("consumeTime"), "endTimeText") == null) {
                endTime = dateToLong(iterateJson(_json.getJSONObject("consumeTime"), "text"));
            }else{
                endTime = dateToLong(iterateJson(_json.getJSONObject("consumeTime"), "endTimeText"));
            }
//            Long endTime = dateToLong(iterateJson(_json.getJSONObject("consumeTime"), "endTimeText"));
            _entity.setEndTime(endTime);
            _entity.setStartTime(startTime);
            if (startTime==0 && endTime==0) {
                String currentTime = null2String(iterateJson(_json.getJSONObject("consumeTime"), "text"));
                _entity.setStartTime(dateToLong(currentTime));
                _entity.setEndTime(dateToLong(currentTime));
            }
            expenseList.add(_entity);
        }

        //校验
        Map<String, Long> travelTime = calFirstTimeUtil(travelList);
        Map<String, Long> expenseTime = calFirstTimeUtil(expenseList);
        if (Objects.isNull(travelTime) || Objects.isNull(expenseTime)) {
            return retMap(true, "行程时间与消费时间一致性校验通过");
        }
        StringBuilder sb = new StringBuilder();
        //todo:临时增加条件 行程有任意三月份的记录 不控制 .过几个月后删除
        if(travelTime.get("startTime")<=1709222400000l){
            return retMap(true, "行程时间与消费时间一致性校验通过-0301");
        }
        if(travelTime.get("startTime")>expenseTime.get("startTime")){
            //检查用
//            System.out.println("最早行程时间==>" + NormalUtil.longToShortTime(travelTime.get("startTime")) + "||最早消费时间==>" + NormalUtil.longToShortTime(expenseTime.get("startTime")));
            sb.append(" 最早行程时间与消费时间不符合，请调整行程或检查并调整消费时间(最早行程时间:" + NormalUtil.longToShortTime(travelTime.get("startTime")) + ",最早消费时间:" + NormalUtil.longToShortTime(expenseTime.get("startTime")) + ")！ ");
        }
        if (travelTime.get("endTime") < expenseTime.get("endTime")) {
            sb.append(" 最晚行程时间与最晚消费时间不符合，请调整行程或检查并调整消费时间(最晚行程时间:"+NormalUtil.longToShortTime(travelTime.get("endTime"))+",最晚消费时间:"+NormalUtil.longToShortTime(expenseTime.get("endTime"))+")!");
        }

        return sb.length() > 0 ? retMap(false, sb.toString()) : retMap(true, "行程时间与消费时间一致性校验通过");
    }

    /**
     * 整理最小时间与最大时间
     * @param list
     */
    private Map<String, Long> calFirstTimeUtil(List list) {
        if (list.isEmpty()) {
            return null;
        }
        //计算最小
        long tmpStartTime= Long.MAX_VALUE;
        long tmpEndTime=Long.MIN_VALUE;
        for (Object _entity : list) {
            if(_entity instanceof TravelEntity){
                TravelEntity entity = (TravelEntity) _entity;
                if(entity.getStartDate()<tmpStartTime){
                    tmpStartTime = entity.getStartDate();
                }
                if (entity.getEndDate() > tmpEndTime) {
                    tmpEndTime = entity.getEndDate();
                }
            }
            if(_entity instanceof ExpenseEntity){
                ExpenseEntity entity = (ExpenseEntity) _entity;
                if(entity.getStartTime()<tmpStartTime){
                    tmpStartTime = entity.getStartTime();
                }
                if (entity.getEndTime() > tmpEndTime) {
                    tmpEndTime = entity.getEndTime();
                }
            }
        }
        Map<String, Long> ret = new HashMap<>();
        ret.put("startTime", tmpStartTime);
        ret.put("endTime", tmpEndTime);
        return ret;
    }

    /**
     * 检查行程客户和费用客户包含不一致
     * 暂时不用了，上面的方法
     * 返回Map flag + message
     */
    @Deprecated
    private Map<String, Object> checkAccount(JSONObject formData) {
        StringBuilder sb = new StringBuilder();
        //获取费用
        JSONArray expenseArray = getObjectArray("expenseList", "value", formData);
        //获取行程
        JSONArray travelArray = getObjectArray("travelRouteList", "value", formData);
        if (Objects.isNull(expenseArray) || expenseArray.isEmpty()) {
            //费用空的
            return retMap(false, "费用是空的，无法校验\n");
        }
        //整理行程中的客户
        List<String> travelList = new ArrayList<>();
        for (Object obj : travelArray) {
            JSONObject _json = JSONObject.parseObject(JSONObject.toJSONString(obj));
            JSONObject _value = _json.getJSONObject("customObject").getJSONObject("CF208");
            if (!Objects.isNull(_value)) {
                travelList.add(_value.getJSONObject("value").getString("text"));

            }
        }

        //整理费用中的客户
        List<String> expenseList = new ArrayList<>();
        for (Object obj : expenseArray) {
            JSONObject _json = JSONObject.parseObject(JSONObject.toJSONString(obj));
            String expenseTypeName = iterateJson(_json.getJSONObject("expenseTypeCode"), "text").toString();
            List<String> _list = Arrays.asList(MCSTR);
            if (!_list.contains(expenseTypeName)) {
                continue;
            }
            JSONObject _value = _json.getJSONObject("CF80").getJSONObject("value");
            if (!Objects.isNull(_value)) {
                expenseList.add(specialStringHandle(_value.getString("text")));
            }
        }

        //开始比较
        for (String s : expenseList) {
            if (!travelList.contains(s)) {
                sb.append("费用中的客户:" + s + " 不存在与行程中，请修改为行程中的客户!\n");
            }
        }
        //先控制下
        //先临时修改 客户的false
        return sb.length() > 0 ? retMap(false, sb.toString()) : retMap(false, "客户一致性检查通过");
    }

    private JSONArray getObjectArray(String jsonCode, String arrayCode, JSONObject formData) {
        try {
            JSONObject _jsonObject = formData.getJSONObject(jsonCode);
            JSONArray _jsonArray = _jsonObject.getJSONArray(arrayCode);
            return _jsonArray;
        } catch (Exception e) {
            log.info("获取 每刻自定义校验报文 转换list出错jsonCode---{},arrayCode{}", jsonCode, arrayCode);
            return new JSONArray();
        }

    }

    //方法标准返回
    private Map<String, Object> retMap(boolean code, String message) {
        Map<String, Object> map = new HashMap<>();
        map.put("code", code);
        map.put("message", message);
        return map;
    }

    /**
     * 获取invoiceInfo 中的时间
     * 有可能是 time  有可能是issueDate
     *
     * @param jsonObject
     */
    private long getDateField(JSONObject jsonObject) {
        if (StringUtils.isNotBlank(jsonObject.getString("issueDate"))) {
            String chinaDate = jsonObject.getString("issueDate");
            long _issueDate = chinaDateToLong(chinaDate, "issueDate");
            return _issueDate;
        }
        if (StringUtils.isNotBlank(jsonObject.getString("time"))) {
            String chinaDate = jsonObject.getString("time");
            long _issueDate = chinaDateToLong(chinaDate, "time");
            return _issueDate;
        }
        return 0;
    }

    /**
     * 长时间戳转为短日期的时间戳
     * @param longDate
     * @return
     */
    private long longDateToShortLongDate(long longDate) {
        if (longDate == 0) {
            return 0;
        }
        //时间戳转 时间
        try {
            Date tmpDate = new Date(longDate);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String tmpDateStr = sdf.format(tmpDate);
            Date tmpDate2 = sdf.parse(tmpDateStr);
            return tmpDate2.getTime();
        } catch (ParseException e) {
            log.info("时间取整异常");
            return 0;
        }
    }

    /**
     * 中文日期类型 转 long型
     *
     * @param s
     * @return
     */
    private long chinaDateToLong(String s, String type) {
        try {
            if (type.equals("issueDate")) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
                Date date = sdf.parse(s);
                return date.getTime();
            }
            if (type.equals("time")) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
                Date date = sdf.parse(s);
                return date.getTime();
            }

        } catch (Exception ex) {
            log.info("时间格式错误，需要修改");
            return 0;
        }
        return 0;
    }

    private long dateToLong(Object s) {
        try{
            //出租车可能出现特殊的string返回值
//            String _getS = s.toString();
//            if (_getS.contains("|||")) {
//                String[] _getSArgs=_getS.split("|||");
//                SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
//                Date date=sdf.parse(_getSArgs[0].toString());
//                return date.getTime();
//            }
            SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
            Date date=sdf.parse(s.toString());
            return date.getTime();
        }catch (Exception ex){
            log.info("提交时间出现异常！！！");
            return 0;
        }
    }

    private String specialStringHandle(String s) {
        try {
            String[] arg = s.split("\\|\\|\\|");
            return arg[arg.length - 1];
        } catch (Exception e) {
            log.info("｜｜｜截取字符串异常");
            return "";
        }
    }

    /**
     * 递归查找 json 子元素
     *
     * @param jsonObject
     * @param valueStr
     * @return
     */
    private Object iterateJson(JSONObject jsonObject, String valueStr) {
            try{
                //先判定是不是空的
                if (Objects.isNull(jsonObject)) {
                    log.info("需要递归的json对象为空--->>需要查询的叶节点>>", valueStr);
                    return null;
                }
                for (String key : jsonObject.keySet()) {
                    Object value = jsonObject.get(key);
                    if (value instanceof JSONObject) {
                        Object _r = iterateJson((JSONObject) value, valueStr);
                        if (!Objects.isNull(_r)) {
                            return _r;
                        }
                    } else {
                        if (key.equals(valueStr)) {
                            return value;
                        }
                    }
                }
            }catch(Exception ex){
                log.info("json递归异常------>>请注意");
                return null;
            }
        return null;
    }
}

@Data
class TravelEntity {
    private long startDate;
    private long endDate;
    //客户名称
    private String accountName;
}

//费用对象
@Data
class ExpenseEntity {
    private long startTime;
    private long endTime;
    private long currentTime; //业务招待用
    private String expenseTypeName;
    private String amountStr;
    private String consumeAmount;
    private String accountName;

}

@Data
class InvoiceEntity {
    private String invoiceCode;
    private String issueDate;
}

